home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2002 #3
/
Amiga Plus CD - 2002 - No. 03.iso
/
AmiSoft
/
Util
/
Arc
/
Checkx.lha
/
CheckX
/
sources
/
CheckX.c
next >
Wrap
C/C++ Source or Header
|
2002-12-30
|
59KB
|
1,928 lines
#define NAME "CheckX"
#define REVISION "92"
#define DISTRIBUTION "(Freeware) "
#define DATE "30.12.2002"
#define VERSION "1"
#define AUTHOR "by Dirk Stöcker <stoecker@epost.de>"
/*
This program scans for crunched, linked files and archived files. It
decrunches them and saves the result files to another directory-tree.
The scanning routines are recursive and thus check really all stuff.
The program must be compiled and linked without startup-code. You can set
the pure file protection bit and make it resident, because it is multi-
reentrant (no global variables, except library bases).
*/
/* Programmheader
Name: CheckX
Author: SDI
Distribution: Freeware
Description: scans, decrunches and dearchives files
Compileropts: -
Linkeropts: -l xfdmaster xpkmaster xadmaster amiga -gsi
1.0 14.12.96 : first Version
1.1 28.12.96 : moved PassRequest into xpkmaster.library
1.2 12.02.97 : now also decrunches Exe-Files
1.3 15.06.97 : added length output as test
1.4 21.11.97 : renamed from Decrunch, got really new program
1.5 22.11.97 : bug-fixes
1.6 29.11.97 : added unarchiving feature
1.7 30.11.97 : bug-fixes
1.8 06.12.97 : xpkmaster.library now only required with ASKPWD option
1.9 07.12.97 : Added archive copy for weird archive names, better error
codes
1.10 08.12.97 : fixed error codes a bit
1.11 11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
to temporary filenames
1.12 12.12.97 : added Arc, ZOO and LhASFX archives
1.13 13.12.97 : fixed Arc recognition
1.14 19.12.97 : deletes copied arc before scan
1.15 22.12.97 : crunched archives are unarchived correctly now
1.16 02.01.98 : opens dos.library itself, no startup-code required
1.17 23.01.98 : added disk crunchers
1.18 24.01.98 : some fixes
1.19 01.02.98 : little bug-fix in argument-option use
1.20 06.02.98 : better error output, added automount
1.21 08.02.98 : little bug-fix
1.22 10.02.98 : fixed archive copy conditions, added PRINTALL
1.23 12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
1.24 13.02.98 : added unstripping
1.25 04.03.98 : added PRINTEXEC
1.26 13.03.98 : added high density DMS support
1.27 19.03.98 : added LOUD keyword
1.28 23.03.98 : RDx no longer depends on archive depth, but on dddepth
1.29 10.04.98 : bug fixes
1.30 26.04.98 : bug fixes
1.31 09.05.98 : now uses no longer adress 4 for SysBase
1.32 31.05.98 : better output
1.33 04.06.98 : added HEADER addition for address files
1.34 08.08.98 : bug fix with SAVE
1.35 24.09.98 : added xvs.library virus checks
1.36 18.10.98 : xvs is opened global and only once
1.37 30.10.98 : renamed from CheckXFD
1.38 11.11.98 : fixed format drive bug using a delay and an error report
1.39 14.11.98 : format error with AUTOMOUNT removed
1.40 16.11.98 : removed HEADER addition stuff
1.41 18.11.98 : better RDx: access and mount
1.42 23.11.98 : fixed bug with hunk stripping
1.43 29.12.98 : now prints an error, when virus detection is turned off,
added time calculation and output
1.44 31.12.98 : little bug fix
1.45 06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
and internal DMS call
1.46 09.02.99 : removed internal LZX call
1.47 11.02.99 : now uses assembler startcode allocating a bigger stack
1.48 14.02.99 : bug-fixes for nocylinder archivers (PackDev)
1.49 16.02.99 : fixed strip option (don't know, where the error was :-)
1.50 21.02.99 : removed internal Zoom call and disk-archiver stuff
1.51 22.02.99 : fixed archiver call for remaining non-XAD archivers, added
empty file check
1.52 23.02.99 : fixed StartCode return value
1.53 24.02.99 : forgot empty check for archived files
1.54 08.03.99 : old archiver calling did not work, when file was XAD
unarchived
1.55 26.03.99 : prints error, when logfile cannot be created
1.56 30.03.99 : added bootblock scanning for unarchived disks
1.57 16.05.99 : bug fix with unlinked file save
1.58 17.07.99 : removed internal LhA Support
1.59 30.07.99 : bug fix with file name prints
1.60 03.08.99 : added DEBUG option
1.61 05.08.99 : added XVS SelfTest and MemoryTest
1.62 19.08.99 : added error summary, again fixed name problem
1.63 14.09.99 : solved big memory loss problem (did not free xadArchiveInfo),
added logfile comment
1.64 17.10.99 : removed external archiver calls, added QUIET
1.65 24.11.99 : now sets nice return values
1.66 26.11.99 : tries reading again before giving read error
1.67 03.12.99 : bug fix in name printing
1.68 04.12.99 : tries again opening files.
1.69 16.12.99 : added NOSILENT Option
1.70 15.01.00 : files from disc archives are extracted directly now,
removed double read tries
1.71 16.01.00 : fixed error messages for disk unarchiving
1.72 12.02.00 : added support for ADF images
1.73 13.02.00 : bug fix for disk archives
1.74 09.03.00 : now detects XADFIF_NOFILENAME and XADFIF_NOUNCRUNCHSIZE
1.75 05.04.00 : fixed bug with XADFIF_NOFILENAME
1.76 26.04.00 : added size checkout for XADFIF_NOUNCRUNCHSIZE
1.77 05.06.00 : added support for multiple filesystems, removed NODOS and
diskerr errors, always prints FS-type now.
1.78 24.07.00 : bug fix
1.79 27.07.00 : bug fix with multi FS support
1.80 14.09.00 : added SAVEALL keyword
1.81 25.03.01 : added support for crypted archives and large archive scan
1.82 05.04.01 : fixed Enforcer hit
1.83 08.04.01 : empty file got warning
1.84 18.04.01 : added texts in case libraries could not be opened
1.85 12.07.01 : added sector checks, reduced final file size
1.86 30.09.01 : sector check is default now, bug fixes
1.87 27.01.02 : added CRC calculation and DEEPNAME option
1.88 31.08.02 : added ASKPWD for disk archives
1.89 06.10.02 : workaround for file 42.zip
1.90 20.11.02 : fixed CRC problem
1.91 29.12.02 : readded bootblock virus detection after XVS changed in this
point.
1.92 30.12.02 : Last version produced to many wrong virus hits, fixed
*/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/xfdmaster.h>
#include <proto/xadmaster.h>
#include <proto/xpkmaster.h>
#include <proto/intuition.h>
#include <proto/xvs.h>
#include <proto/utility.h>
#include <libraries/xfdmaster.h>
#include <dos/dostags.h>
#include <dos/doshunks.h>
#include <dos/filehandler.h>
#include <exec/memory.h>
#include "SDI_compiler.h"
#define PARAM "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,PRINTALL/S,PRINTEXEC/S," \
"NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S," \
"NOSECTOR/S,NOSILENT/S,NOSTRIP/S,NOVIRUS/S," \
"DEBUG/S,QUIET/S,SAVEALL/S,CRC/S,DEEPNAME/S"
#define version "$VER: " NAME " " VERSION "." REVISION " (" DATE ") " DISTRIBUTION AUTHOR
void RawPutChar(ULONG c);
#ifdef __SASC
#pragma libcall SysBase RawPutChar 204 001
#elif defined(__GNUC__)
#define RawPutChar(c) LP1NR(204, RawPutChar, ULONG, c, d0, , SysBase)
#else
#pragma amicall(SysBase,0x204,RawPutChar(d0))
#endif
#define PASSWORDSIZE 100
struct FileData {
struct CrunchMemList * fd_MemList; /* list of all memory allocations */
#ifdef __SASC
struct xfdMasterBase * fd_xfdMasterBase;
struct Library * fd_xvsBase;
struct xadMasterBase * fd_xadMasterBase;
struct DosLibrary * fd_DOSBase;
struct ExecBase * fd_SysBase;
#endif
ULONG * fd_CRCBuf; /* the CRC table */
STRPTR fd_Name; /* the file name */
STRPTR fd_Memory; /* for bootblock checks */
BPTR fd_LogFileFH; /* FileHandle of log file */
BPTR fd_ArcFileFH; /* FileHandle in case of large archive */
ULONG fd_SaveDirL; /* Lock to save directory */
ULONG fd_Flags; /* the argument and status flags */
ULONG fd_NumVirus; /* total number of viruses */
ULONG fd_NumSectors; /* total number of currupted sectors */
ULONG fd_CHKXErrors; /* total number of CheckX errors */
ULONG fd_CHKXWarnings; /* total number of CheckX warnings - not printed yet */
ULONG fd_XFDErrors; /* total number of XFD errors */
ULONG fd_XADErrors; /* total number of XAD errors */
ULONG fd_CorruptedArchives; /* total number of corrupted archives */
ULONG fd_CRC32; /* the CRC of current buffer */
UBYTE fd_RecurseDepth; /* depth of recursion */
UBYTE fd_LinkNum; /* number of unlinked part */
UBYTE fd_Password[PASSWORDSIZE];/* the last allocated passwort */
};
typedef struct xadMasterBase XADMASTERBASE;
typedef struct xfdMasterBase XFDMASTERBASE;
typedef struct Library XVSBASE;
#ifdef __SASC
static struct ExecBase *sysbase;
#define XpkBase xpkbase
#define ASSIGN_XPK
#define IntuitionBase intuitionbase
#define ASSIGN_INT
#define UtilityBase utilitybase
#define ASSIGN_UTIL
#define xfdMasterBase fd->fd_xfdMasterBase
#define ASSIGN_SYS sysbase = fd->fd_SysBase = (*((struct ExecBase **) 4));
#define SysBase fd->fd_SysBase
#define DOSBase fd->fd_DOSBase
#define ASSIGN_DOS DOSBase = dosbase;
#define xvsBase fd->fd_xvsBase
#define xadMasterBase fd->fd_xadMasterBase
#else
struct Library * XpkBase;
struct IntuitionBase * IntuitionBase;
struct UtilityBase * UtilityBase;
#define ASSIGN_XPK XpkBase = xpkbase;
#define ASSIGN_INT IntuitionBase = intuitionbase;
#define ASSIGN_UTIL UtilityBase = utilitybase;
#define ASSIGN_SYS SysBase = (*((struct ExecBase **) 4));
#define ASSIGN_DOS DOSBase = dosbase;
struct xfdMasterBase * xfdMasterBase;
struct Library * xvsBase;
struct xadMasterBase * xadMasterBase;
struct DosLibrary * DOSBase;
struct ExecBase * SysBase;
#endif
struct Args {
STRPTR from;
STRPTR log;
STRPTR save;
ULONG all;
ULONG askpwd;
ULONG printall;
ULONG printexec;
ULONG nodecrunch;
ULONG nounlink;
ULONG nounarchive;
ULONG nountrack;
ULONG nosector;
ULONG nosilent;
ULONG nostrip;
ULONG novirus;
ULONG debug;
ULONG quiet;
ULONG saveall;
ULONG crc;
ULONG deepname;
};
struct CrunchMemList {
struct CrunchMemList * cml_Next;
APTR cml_MemoryRegion;
ULONG cml_MemorySize;
};
#define CHECKXFLAG_SAVE (1<< 0)
#define CHECKXFLAG_ALL (1<< 1)
#define CHECKXFLAG_ASKPWD (1<< 2)
#define CHECKXFLAG_PRINTALL (1<< 3)
#define CHECKXFLAG_PRINTEXEC (1<< 4)
#define CHECKXFLAG_NODECRUNCH (1<< 5)
#define CHECKXFLAG_NOSECTOR (1<< 6)
#define CHECKXFLAG_NOUNLINK (1<< 7)
#define CHECKXFLAG_NOUNARCHIVE (1<< 8)
#define CHECKXFLAG_NOUNTRACK (1<< 9)
#define CHECKXFLAG_NOSTRIP (1<<10)
#define CHECKXFLAG_DEBUG (1<<11)
#define CHECKXFLAG_QUIET (1<<12)
#define CHECKXFLAG_SAVEALL (1<<13)
#define CHECKXFLAG_CRC (1<<14)
#define CHECKXFLAG_DEEPNAME (1<<15)
#define CHECKXFLAG_XVSLIB (1<<20)
#define CHKXCALLFLAGS (CHECKXFLAG_SAVE|CHECKXFLAG_ALL| \
CHECKXFLAG_ASKPWD|CHECKXFLAG_PRINTALL| \
CHECKXFLAG_PRINTEXEC|CHECKXFLAG_NODECRUNCH| \
CHECKXFLAG_NOUNLINK|CHECKXFLAG_NOUNARCHIVE| \
CHECKXFLAG_NOUNTRACK|CHECKXFLAG_NOSTRIP| \
CHECKXFLAG_DEBUG|CHECKXFLAG_QUIET| \
CHECKXFLAG_XVSLIB|CHECKXFLAG_SAVEALL| \
CHECKXFLAG_NOSECTOR|CHECKXFLAG_CRC| \
CHECKXFLAG_DEEPNAME)
#define CHKXSAVEFLAGS (CHECKXFLAG_LINKED|CHECKXFLAG_CRUNCHED| \
CHECKXFLAG_STRIPPED|CHECKXFLAG_SAVEALL)
#define CHKXNAMEFLAGS (CHECKXFLAG_NAMEPRINTED|CHECKXFLAG_CRCVALID| \
CHECKXFLAG_SHORTNAME)
#define CHECKXFLAG_MASTERTEXT (1<<22) /* texts unrelated to files */
#define CHECKXFLAG_SHORTNAME (1<<23)
#define CHECKXFLAG_CRCVALID (1<<24)
#define CHECKXFLAG_BBEXTRACTED (1<<25)
#define CHECKXFLAG_NAMEPRINTED (1<<26)
#define CHECKXFLAG_CRUNCHED (1<<27)
#define CHECKXFLAG_LINKED (1<<28)
#define CHECKXFLAG_ADDRESS (1<<29)
#define CHECKXFLAG_NOFREEMEM (1<<30)
#define CHECKXFLAG_STRIPPED (1<<31)
#define CHXWARN_OFFSET 30
#define XADERR_OFFSET 0x100
#define XFDERR_OFFSET 0x200
#define CHKXERR_NOMEMORY 1
#define CHKXERR_EXAMINEERR 2
#define CHKXERR_OPENERR 3
#define CHKXERR_READ 4
#define CHKXERR_SCANERR 5
#define CHKXERR_BREAK 6
#define CHKXERR_OPENDIR 7
#define CHKXERR_RESOURCE 8
#define CHKXERR_NOBOOTVIRUS 9
#define CHKXERR_WRITE 10
#define CHKXERR_NOVIRUS 11
#define CHKXERR_NOMEMORYARC 12
#define CHKXERR_NOSECTOR 13
#define CHKXWARN_NOVIRUS 31
#define CHKXWARN_XVSSELFTEST 32
#define CHKXWARN_MEMVIRUS 33
#define CHKXWARN_EMPTY 34
static void SetLogComment(struct FileData *, STRPTR);
static LONG DoDirectoryScan(struct FileData *, STRPTR, STRPTR);
static LONG DoFileOpen(struct FileData *);
static LONG DoGetVirus(struct FileData *, APTR, ULONG);
static LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
static LONG DoFileUnLink(struct FileData *, APTR, ULONG);
static LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
static LONG DoFileStrip(struct FileData *, APTR, ULONG);
static void PrintCHKXFile(struct FileData *);
static void PrintCHKXErr(struct FileData *, LONG);
static void PrintCHKXTxt(struct FileData *, STRPTR, ...);
static LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
static void FreeCrunchMemList(struct FileData *, APTR);
static LONG SaveUncrFile(struct FileData *, APTR, ULONG);
static ULONG OpenParentDir(struct FileData *);
static ULONG OpenNewDir(struct FileData *, STRPTR);
static LONG DoSectorCheck(struct FileData *, APTR, ULONG, ULONG);
static void clear(STRPTR, ULONG);
static void SPrintF(struct FileData *, STRPTR buf, STRPTR format, ...);
static ASM(void) KPutC(REG(d0, ULONG c), REG(a3, struct FileData *));
static void KPrintf(struct FileData *, STRPTR fmt, ...);
static ASM(LONG) BreakHookCheckX(void);
static const struct Hook breakhook = {{0,0},(ULONG (*)()) BreakHookCheckX, 0};
/* All memory regions must be in mem list. All unneeded memory must be freed
as fast as possible (after unlinking, decrunching), as well as the
MemoryList structure.
The program has a loop like scan routine system, which is called for
every file:
A) Scan files, directories and sub directories and call following for
every file:
1) Check for viruses.
2) Test if it is an archive. When yes decrunch and start for every file
with point 1.
3) Test if file is linked. When yes unlink and call point 1 for both
parts.
4) Test if file is crunched. When yes, decrunch and start again with
point 1.
5) Try stripping useless stuff. When successful start with point 1 again.
6) Possibly save file (with SAVE option) or end loop here.
*/
/* main routine, do argument parsing */
LONG start(void)
{
LONG error = RETURN_FAIL;
struct FileData fd[1];
struct DosLibrary *dosbase;
struct Process *task;
clear((STRPTR)fd, sizeof(struct FileData));
ASSIGN_SYS
/* test for WB and reply startup-message */
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
XFDMASTERBASE * xfdmasterbase;
ASSIGN_DOS
if((xfdmasterbase = (XFDMASTERBASE *) OpenLibrary("xfdmaster.library", 39)))
{
XADMASTERBASE *xadmasterbase;
xfdMasterBase = xfdmasterbase;
if((xadmasterbase = (XADMASTERBASE *) OpenLibrary("xadmaster.library", 10)))
{
struct Args Args;
struct RDArgs *rda;
xadMasterBase = xadmasterbase;
clear((STRPTR)(&Args), sizeof(struct Args));
if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
{
rda->RDA_ExtHelp = version; /* is removed by optimizer */
rda->RDA_ExtHelp =
"FROM source file or directory - may contain patterns\n"
"LOG log file name\n"
"SAVE directory, where decrunched files are saved\n"
"ALL scan deep into directories\n"
"ASKPWD ask for password when needed (needs xpkmaster.library)\n"
"PRINTALL print all filenames\n"
"PRINTEXEC print names of all executable files\n"
"NODECRUNCH do not decrunch files with xfdmaster\n"
"NOUNLINK do not unlink files with xfdmaster\n"
"NOUNARCHIVE do not unarchive file archives with xadmaster\n"
"NOUNTRACK do not unarchive track archives with xadmaster\n"
"NOSECTOR do not check the files for virus infected sectors\n"
"NOSILENT do not disable dos requests\n"
"NOSTRIP do not strip useless hunks\n"
"NOVIRUS do not scan with xvs.library for viruses\n"
"DEBUG also output texts to serial debug engine\n"
"QUIET do not output texts to console\n"
"SAVEALL saves all files (also uncrunched) except address files\n"
"CRC print CRC32 in fornt of each filename\n"
"DEEPNAME print own name for every part (e.g. unliked parts)\n";
if(ReadArgs(PARAM, (LONG *) &Args, rda))
{
ULONG flags = 0, log = 0;
XVSBASE *xvsbase = 0;
if(!Args.from) Args.from = "#?";
if(Args.all) flags |= CHECKXFLAG_ALL;
if(Args.save) flags |= CHECKXFLAG_SAVE;
if(Args.saveall) flags |= CHECKXFLAG_SAVEALL;
if(Args.askpwd) flags |= CHECKXFLAG_ASKPWD;
if(Args.printall) flags |= CHECKXFLAG_PRINTALL;
if(Args.printexec) flags |= CHECKXFLAG_PRINTEXEC;
if(Args.nodecrunch) flags |= CHECKXFLAG_NODECRUNCH;
if(Args.nounlink) flags |= CHECKXFLAG_NOUNLINK;
if(Args.nounarchive) flags |= CHECKXFLAG_NOUNARCHIVE;
if(Args.nountrack) flags |= CHECKXFLAG_NOUNTRACK;
if(Args.nostrip) flags |= CHECKXFLAG_NOSTRIP;
if(Args.debug) flags |= CHECKXFLAG_DEBUG;
if(Args.quiet) flags |= CHECKXFLAG_QUIET;
if(Args.nosector) flags |= CHECKXFLAG_NOSECTOR;
if(Args.deepname) flags |= CHECKXFLAG_DEEPNAME;
/*if(Args.crc)*/
{
if((fd->fd_CRCBuf = (ULONG *) AllocMem(4*256, MEMF_ANY)))
{
ULONG i, j, k;
if(Args.crc)
flags |= CHECKXFLAG_CRC;
for(i = 0; i < 256; ++i)
{
k = i;
for(j = 0; j < 8; ++j)
{
if(k & 1)
k = (k >> 1) ^ 0xEDB88320;
else
k >>= 1;
}
fd->fd_CRCBuf[i] = k;
}
}
}
if(!Args.novirus)
{
if((xvsbase = (XVSBASE *) OpenLibrary("xvs.library", 33)))
{
flags |= CHECKXFLAG_XVSLIB;
xvsBase = xvsbase;
}
}
if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
{
APTR win;
ULONG s1 = 0, s2 = 0, msecs;
struct IntuitionBase *intuitionbase;
win = task->pr_WindowPtr;
if(!Args.nosilent)
task->pr_WindowPtr = (APTR) -1;
/* prevent dos requests */
if(log)
{
SetFileSize(log, 0, OFFSET_BEGINNING);
SetProtection(Args.log, FIBF_EXECUTE);
SetLogComment(fd, Args.log);
}
fd->fd_Flags = flags | CHECKXFLAG_MASTERTEXT;
fd->fd_LogFileFH = log;
if(!xvsbase)
PrintCHKXErr(fd, CHKXWARN_NOVIRUS);
else
{
struct xvsMemoryInfo *mi;
if(!xvsSelfTest())
PrintCHKXErr(fd, CHKXWARN_XVSSELFTEST);
if((mi = (struct xvsMemoryInfo *) xvsAllocObject(XVSOBJ_MEMORYINFO)))
{
if(xvsSurveyMemory(mi))
PrintCHKXErr(fd, CHKXWARN_MEMVIRUS);
xvsFreeObject(mi);
}
}
if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
{
ASSIGN_INT
CurrentTime(&s1, &msecs);
}
++fd->fd_RecurseDepth;
fd->fd_Flags &= ~(CHECKXFLAG_MASTERTEXT);
error = DoDirectoryScan(fd, Args.from, Args.save);
--fd->fd_RecurseDepth;
fd->fd_Flags = flags | CHECKXFLAG_MASTERTEXT;
if(error)
{
PrintCHKXErr(fd, error);
error = RETURN_FAIL;
}
task->pr_WindowPtr = win;
if(intuitionbase)
{
CurrentTime(&s2, &msecs);
s2 -= s1;
s1 = s2 / 60;
s2 %= 60;
msecs = s1 / 60;
s1 %= 60;
PrintCHKXTxt(fd, "\nTime needed for check: %2ld:%02ld:%02ld", msecs, s1, s2);
CloseLibrary((struct Library *) intuitionbase);
}
if(fd->fd_NumVirus && !fd->fd_NumSectors)
PrintCHKXTxt(fd, "The scan detected %ld virus%s.", fd->fd_NumVirus, fd->fd_NumVirus > 1 ? "es" : "");
else if(fd->fd_NumVirus && fd->fd_NumSectors)
PrintCHKXTxt(fd, "The scan detected %ld virus%s and %ld defective sector%s.", fd->fd_NumVirus,
fd->fd_NumVirus > 1 ? "es" : "", fd->fd_NumSectors, fd->fd_NumSectors > 1 ? "s" : "");
else if(!fd->fd_NumVirus && fd->fd_NumSectors)
PrintCHKXTxt(fd, "The scan detected %ld defective sector%s.", fd->fd_NumSectors,
fd->fd_NumSectors > 1 ? "s" : "");
if(fd->fd_CHKXErrors || fd->fd_XADErrors || fd->fd_XFDErrors || fd->fd_CorruptedArchives)
PrintCHKXTxt(fd, "There were errors (CheckX/XFD/XAD/corrupted archives): %ld/%ld/%ld/%ld.",
fd->fd_CHKXErrors, fd->fd_XFDErrors, fd->fd_XADErrors, fd->fd_CorruptedArchives);
if(!error && (fd->fd_NumVirus || !xvsBase))
{
SetIoErr(0);
error = RETURN_WARN;
}
if(log)
Close(log);
}
else if(Args.log && !Args.quiet)
Printf("Could not create logfile.\n");
if(xvsbase)
CloseLibrary((struct Library *) xvsbase);
if(fd->fd_CRCBuf)
FreeMem(fd->fd_CRCBuf, 4*256);
FreeArgs(rda);
}
else
PrintFault(IoErr(), "CheckX");
FreeDosObject(DOS_RDARGS, rda);
}
CloseLibrary((struct Library *) xadmasterbase);
}
else
Printf("CheckX requires xadmaster.library version 10 or better.\n");
CloseLibrary((struct Library *) xfdmasterbase);
}
else
Printf("CheckX requires xfdmaster.library version 39 or better.\n");
CloseLibrary((struct Library *) dosbase);
}
return error;
}
static void clear(STRPTR buf, ULONG size)
{
while(size--)
*(buf++) = 0;
}
static void SetLogComment(struct FileData *fd, STRPTR name)
{
UBYTE com[30];
struct MsgPort *TimerMP;
if((TimerMP = CreateMsgPort()))
{
struct timerequest *TimerIO;
if((TimerIO = (struct timerequest *) CreateIORequest(TimerMP,
sizeof(struct timerequest))))
{
if(!OpenDevice("timer.device",UNIT_VBLANK,
(struct IORequest *)TimerIO,0))
{
struct UtilityBase *utilitybase;
TimerIO->tr_node.io_Command = TR_GETSYSTIME;
DoIO((struct IORequest *) TimerIO);
if((utilitybase = (struct UtilityBase *) OpenLibrary("utility.library",37)))
{
struct ClockData dat;
ASSIGN_UTIL
Amiga2Date(TimerIO->tr_time.tv_secs, &dat);
SPrintF(fd, com, "CheckX " VERSION "." REVISION " - %02ld.%02ld.%ld", dat.mday, dat.month, dat.year);
CloseLibrary((struct Library *) utilitybase);
SetComment(name, com);
}
CloseDevice((struct IORequest *) TimerIO);
}
DeleteIORequest(TimerIO);
}
DeleteMsgPort(TimerMP);
}
}
/* This scans a directory and calls DoFileOpen for every file. It
automatically creates SAVE destination directories when necessary. */
static LONG DoDirectoryScan(struct FileData *fd, STRPTR name, STRPTR sav)
{
struct AnchorPath *APath;
LONG error = CHKXERR_SCANERR;
ULONG retval;
if(!(fd->fd_Flags & CHECKXFLAG_SAVE) || !sav ||
(fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
{
if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
512, MEMF_PUBLIC|MEMF_CLEAR)))
{
fd->fd_Name = APath->ap_Buf;
APath->ap_Strlen = 256;
for(retval = MatchFirst(name, APath); !retval;
retval = MatchNext(APath))
{
if(APath->ap_Flags & APF_DIDDIR)
{
OpenParentDir(fd);
APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
}
else if(APath->ap_Info.fib_DirEntryType > 0)
{
if(fd->fd_Flags & CHECKXFLAG_ALL)
{
OpenNewDir(fd, APath->ap_Info.fib_FileName);
APath->ap_Flags |= APF_DODIR;
}
}
else
{
fd->fd_Flags &= CHKXCALLFLAGS;
fd->fd_LinkNum = 0;
PrintCHKXErr(fd, DoFileOpen(fd));
while(fd->fd_MemList)
FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
}
if((fd->fd_Flags & CHECKXFLAG_SAVE) && !fd->fd_SaveDirL)
{
error = CHKXERR_OPENDIR; break;
}
if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
{
error = CHKXERR_BREAK; break;
}
}
MatchEnd(APath);
if(retval == ERROR_NO_MORE_ENTRIES)
error = 0;
FreeMem(APath, sizeof(struct AnchorPath) + 512);
}
else
error = CHKXERR_NOMEMORY;
if(sav && fd->fd_SaveDirL)
UnLock(fd->fd_SaveDirL);
}
else
error = CHKXERR_OPENDIR;
return error;
}
/* Open a file and call DoGetVirus to scan */
static LONG DoFileOpen(struct FileData *fd)
{
struct FileInfoBlock *fib;
LONG ret = 0;
if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
ULONG fh;
if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
{
if(ExamineFH(fh, fib))
{
APTR mem;
if(!fib->fib_Size)
ret = CHKXWARN_EMPTY;
else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
{
if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
ret = CHKXERR_READ;
if(!ret && !(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
ret = DoGetVirus(fd, mem, fib->fib_Size);
else
FreeMem(mem, fib->fib_Size);
}
else
{
fd->fd_ArcFileFH = fh;
PrintCHKXErr(fd, CHKXERR_NOMEMORYARC);
ret = DoFileUnArchive(fd, 0, fib->fib_Size);
}
}
else
ret = CHKXERR_EXAMINEERR;
Close(fh);
}
else
ret = CHKXERR_OPENERR;
FreeDosObject(DOS_FIB, fib);
}
else
ret = CHKXERR_NOMEMORY;
return ret;
}
/* for SAVE option: open parent directory and try to delete the directory
we leave. This only succeeds, when the directory is empty. */
static ULONG OpenParentDir(struct FileData *fd)
{
ULONG g;
UBYTE name[300];
if((g = fd->fd_SaveDirL))
{
NameFromLock(g, name, 300);
fd->fd_SaveDirL = ParentDir(g);
UnLock(g);
DeleteFile(name);
}
else
return -1;
return fd->fd_SaveDirL;
}
/* Open a new subdirectory for SAVE option */
static ULONG OpenNewDir(struct FileData *fd, STRPTR name)
{
ULONG g;
if(fd->fd_SaveDirL)
{
g = CurrentDir(fd->fd_SaveDirL);
if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
if((fd->fd_SaveDirL = CreateDir(name)))
ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
UnLock(CurrentDir(g));
}
else
return -1;
return fd->fd_SaveDirL;
}
static LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
{
if(fd->fd_Flags & CHECKXFLAG_DEEPNAME)
{
if(fd->fd_Flags & CHECKXFLAG_NAMEPRINTED)
{
fd->fd_Flags &= ~(CHECKXFLAG_NAMEPRINTED);
fd->fd_Flags |= CHECKXFLAG_SHORTNAME;
}
}
if(fd->fd_Flags & CHECKXFLAG_CRC && buflength)
{
register ULONG CRC = ~0, i;
fd->fd_Flags |= CHECKXFLAG_CRCVALID;
for(i = 0; i < buflength; ++i)
CRC = fd->fd_CRCBuf[(CRC ^ ((STRPTR)buffer)[i]) & 0xFF] ^ (CRC >> 8);
fd->fd_CRC32 = ~CRC;
}
if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && buflength > 4
&& *((ULONG *)buffer) == HUNK_HEADER))
PrintCHKXFile(fd);
if(!buflength) /* restarted with empty file */
return CHKXWARN_EMPTY;
if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
{
register APTR mem;
if((mem = AllocMem(buflength, MEMF_ANY)))
{
struct xvsFileInfo *fi;
if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
{
register ULONG i;
struct xvsBootInfo *bi;
bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO);
/* xvs may modify the buffer! */
CopyMem(buffer, mem, buflength);
fi->xvsfi_File = mem;
fi->xvsfi_FileLen = buflength;
i = xvsCheckFile(fi);
if(i == XVSFT_DATAVIRUS)
{
PrintCHKXTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_FILEVIRUS)
{
PrintCHKXTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(i == XVSFT_LINKVIRUS)
{
PrintCHKXTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
++fd->fd_NumVirus;
}
else if(bi)
{
bi->xvsbi_Bootblock = mem;
if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
{
PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
++fd->fd_NumVirus;
}
}
if(bi)
{
STRPTR p, pe;
p = (STRPTR)mem+1;
pe = (STRPTR)mem+buflength-1024;
for(;;)
{
while(p <= pe && (p[0] != 'D' || p[1] != 'O' || p[2] != 'S' ||
p[3] > 7))
++p;
if(p <= pe)
{
bi->xvsbi_Bootblock = p;
if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
{
PrintCHKXTxt(fd, "Boot-Virus '%s' at offset $%lx", bi->xvsbi_Name,
p-(STRPTR)mem);
++fd->fd_NumVirus;
p += 1024;
}
else
p += 4;
}
else
break;
}
xvsFreeObject(bi);
}
xvsFreeObject(fi);
}
else
PrintCHKXErr(fd, CHKXERR_NOVIRUS);
FreeMem(mem, buflength);
}
else
PrintCHKXErr(fd, CHKXERR_NOVIRUS);
if(!(fd->fd_Flags & CHECKXFLAG_NOSECTOR))
PrintCHKXErr(fd, DoSectorCheck(fd, buffer, buflength, 0));
}
return DoFileUnArchive(fd, buffer, buflength);
}
static LONG DoSectorCheck(struct FileData *fd, APTR buffer, ULONG buflength, ULONG pos)
{
LONG err = 0;
if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
{
struct xvsSectorInfo *si;
if((si = (struct xvsSectorInfo *) xvsAllocObject(XVSOBJ_SECTORINFO)))
{
ULONG i, j, k;
j = buflength >> 9; /* divide by 512 */
for(i = 0; i < j; ++i)
{
si->xvssi_Sector = ((STRPTR) buffer) + (i<<9);
si->xvssi_Key = pos + i;
k = xvsCheckSector(si);
if(k == XVSST_DESTROYED)
{
++fd->fd_NumSectors;
PrintCHKXTxt(fd, "Sector %ld destroyed by '%s'", si->xvssi_Key, si->xvssi_Name);
}
else if(k == XVSST_INFECTED)
{
++fd->fd_NumSectors;
PrintCHKXTxt(fd, "Sector %ld infected by '%s'", si->xvssi_Key, si->xvssi_Name);
}
}
xvsFreeObject(si);
}
else
err = CHKXERR_NOSECTOR;
}
return err;
}
/* For bootblocks */
static ASM(LONG) OutHookCheckX(REG(a0, struct Hook *hook), REG(a1, struct xadHookParam *hp))
{
LONG i, j;
STRPTR s;
struct FileData *fd;
fd = (struct FileData *) hook->h_Data;
switch(hp->xhp_Command)
{
case XADHC_WRITE:
j = hp->xhp_BufferSize;
s = (STRPTR) hp->xhp_BufferPtr;
if((i = 1024-hp->xhp_DataPos) > j)
i = j;
if(i > 0)
{
CopyMem(s, fd->fd_Memory+hp->xhp_DataPos, i);
hp->xhp_DataPos += i;
j -= i;
s += i;
}
if(hp->xhp_DataPos == 1024 && i > 0)
{
fd->fd_Flags |= CHECKXFLAG_BBEXTRACTED;
if(((fd->fd_Flags & CHECKXFLAG_XVSLIB) && !(fd->fd_Flags & CHECKXFLAG_NOSECTOR)))
{
i = DoSectorCheck(fd, fd->fd_Memory, 1024, 0);
if(i)
{
PrintCHKXErr(fd, i);
return 10000;
}
}
else
return 10000;
}
if(hp->xhp_DataPos >= 1024)
{
LONG k;
while(j)
{
k = hp->xhp_DataPos & 0x1FF;
if((i = 512-k) > j)
i = j;
CopyMem(s, fd->fd_Memory+1024+k, i);
hp->xhp_DataPos += i;
j -= i;
s += i;
if(!(hp->xhp_DataPos & 0x1FF))
{
i = DoSectorCheck(fd, fd->fd_Memory+1024, 512, (hp->xhp_DataPos>>9)-1);
if(i)
{
PrintCHKXErr(fd, i);
return 10000;
}
}
}
}
case XADHC_INIT:
case XADHC_FREE:
case XADHC_ABORT:
break;
default: return XADERR_NOTSUPPORTED;
}
return 0;
}
/* To get real file size */
static ASM(LONG) OutHookCheckXSize(REG(a0, struct Hook *hook), REG(a1, struct xadHookParam *hp))
{
switch(hp->xhp_Command)
{
case XADHC_WRITE:
hp->xhp_DataPos += hp->xhp_BufferSize;
hook->h_Data = (APTR) hp->xhp_DataPos;
case XADHC_INIT:
case XADHC_FREE:
case XADHC_ABORT:
break;
default: return XADERR_NOTSUPPORTED;
}
return 0;
}
static void CheckArcFiles(struct FileData *fd, struct xadArchiveInfo *ai, ULONG disk)
{
struct xadFileInfo *fi;
struct TagItem ti[6];
LONG numloop = 0;
LONG trypwd = 0;
ti[0].ti_Tag = XAD_OUTMEMORY;
ti[1].ti_Tag = XAD_OUTSIZE;
ti[2].ti_Tag = XAD_ENTRYNUMBER;
ti[3].ti_Tag = XAD_PROGRESSHOOK;
ti[3].ti_Data = (ULONG) &breakhook;
ti[4].ti_Tag = TAG_DONE;
fi = ai->xai_FileInfo;
while(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && fi)
{
APTR dest;
if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
{
LONG err = 0;
ULONG flags, size, linknum;
flags = fd->fd_Flags;
linknum = fd->fd_LinkNum;
fd->fd_LinkNum = 0;
if(!(fi->xfi_Flags & XADFIF_NOFILENAME))
fd->fd_Flags &= ~(CHKXNAMEFLAGS);
fd->fd_Name = fi->xfi_FileName;
fd->fd_RecurseDepth++;
size = fi->xfi_Size;
if(fi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
{
struct Hook hook = {{0,0},(ULONG (*)()) OutHookCheckXSize, 0, 0};
struct TagItem ti[5];
ti[0].ti_Tag = XAD_OUTHOOK;
ti[0].ti_Data = (ULONG) &hook;
ti[1].ti_Tag = XAD_ENTRYNUMBER;
ti[1].ti_Data = fi->xfi_EntryNumber;
ti[2].ti_Tag = XAD_PROGRESSHOOK;
ti[2].ti_Data = (ULONG) &breakhook;
ti[3].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
ti[3].ti_Data = (ULONG) fd->fd_Password;
ti[4].ti_Tag = TAG_DONE;
if(!(err = (disk ? xadDiskFileUnArcA(ai, ti) : xadFileUnArcA(ai, ti))))
size = (ULONG) hook.h_Data;
}
if(!size)
{
if(!err)
err = CHKXWARN_EMPTY;
}
else if((dest = AllocMem(size, MEMF_PUBLIC)))
{
if(!(err = AddCrunchMemList(fd, dest, size)))
{
ti[0].ti_Data = (ULONG) dest;
ti[1].ti_Data = size;
ti[2].ti_Data = fi->xfi_EntryNumber;
ti[4].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
ti[4].ti_Data = (ULONG) fd->fd_Password;
if((err = disk ? xadDiskFileUnArcA(ai, ti) : xadFileUnArcA(ai, ti)))
{
if(disk)
err = CHKXERR_READ;
else
err += XADERR_OFFSET;
}
else
err = DoGetVirus(fd, dest, size);
FreeCrunchMemList(fd, dest);
}
else
FreeMem(dest, size);
}
else
err = CHKXERR_NOMEMORY;
if((err == XADERR_OFFSET + XADERR_PASSWORD) && !numloop)
{
if(!trypwd && fd->fd_Password[0])
{
++trypwd; err = 0; numloop = -2;
}
else
{
struct Library *xpkbase;
if((fd->fd_Flags & CHECKXFLAG_ASKPWD) && (xpkbase = OpenLibrary(XPKNAME, 4)))
{
if(!XpkPassRequestTags(XPK_PasswordBuf, fd->fd_Password, XPK_PassBufSize,
PASSWORDSIZE, XPK_PassTitle, fd->fd_Name, TAG_DONE))
{
numloop = -1; err = 0;
++trypwd;
}
CloseLibrary(xpkbase);
}
}
}
if(err)
{
if(fi->xfi_Flags & XADFIF_NOFILENAME)
fd->fd_Flags &= ~(CHKXNAMEFLAGS);
PrintCHKXErr(fd, err);
}
--fd->fd_RecurseDepth;
fd->fd_Flags = flags;
fd->fd_LinkNum = linknum;
}
if(++numloop)
{
fi = fi->xfi_Next;
numloop = 0;
}
else
++numloop;
}
}
/* Tests if a file is an archive. When yes, the archive is unarchived and
the result files are scanned. Else DoFileUnLink is called.
*/
static LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG err = 0;
struct TagItem tih[2];
struct xadArchiveInfo *ai;
if(buflength == 42374 && !(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE))
{
if(!(fd->fd_Flags & CHECKXFLAG_CRCVALID) && fd->fd_CRCBuf)
{
register ULONG CRC = ~0, i;
fd->fd_Flags |= CHECKXFLAG_CRCVALID;
for(i = 0; i < buflength; ++i)
CRC = fd->fd_CRCBuf[(CRC ^ ((STRPTR)buffer)[i]) & 0xFF] ^ (CRC >> 8);
fd->fd_CRC32 = ~CRC;
}
if(fd->fd_CRC32 == 0x9A0D79CC) /* strange unscanable file (in useful times :-) */
{
PrintCHKXErr(fd, CHKXERR_EXAMINEERR);
err = DoFileUnLink(fd, buffer, buflength);
}
}
if(buffer) { tih[0].ti_Tag = XAD_INMEMORY; tih[0].ti_Data = (ULONG) buffer; }
else { tih[0].ti_Tag = XAD_INFILEHANDLE; tih[0].ti_Data = (ULONG) fd->fd_ArcFileFH; }
tih[1].ti_Tag = TAG_DONE;
if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
{
STRPTR arcname;
arcname = fd->fd_Name;
if(!xadGetInfo(ai, XAD_INSIZE, buflength, XAD_PROGRESSHOOK, &breakhook, TAG_MORE, tih))
{
if(ai->xai_Flags & XADAIF_FILECORRUPT)
{
++fd->fd_CorruptedArchives;
PrintCHKXTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
}
else
PrintCHKXTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
if(!(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo))
{
if(buffer)
err = DoFileUnLink(fd, buffer, buflength);
}
else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
err = CHKXERR_OPENERR;
else
{
if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
CheckArcFiles(fd, ai, 0);
if(!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo)
{
STRPTR buf;
/* reduce stacksize, as we have a recursive program */
if((buf = (STRPTR) AllocMem(1024+512, MEMF_PUBLIC)))
{
LONG numloop = 0; LONG trypwd = 0;
ULONG flags;
STRPTR name;
struct xadDiskInfo *di;
struct xadArchiveInfo *aid;
di = ai->xai_DiskInfo;
flags = fd->fd_Flags;
name = fd->fd_Name;
while(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && di)
{
if((di->xdi_Flags & XADDIF_CRYPTED) && fd->fd_Password[0])
trypwd = 1;
if(di->xdi_SectorSize != 512 || (di->xdi_TrackSectors != 11 &&
di->xdi_TrackSectors != 22) || (!(di->xdi_Flags & XADDIF_NOHEADS) &&
di->xdi_Heads != 2) || (!(di->xdi_Flags & XADDIF_NOCYLINDERS) &&
di->xdi_Cylinders != 80))
SPrintF(fd, buf, "-disk image %ld", di->xdi_EntryNumber);
else
{
if(!(di->xdi_Flags & (XADDIF_NOHIGHCYL|XADDIF_NOLOWCYL)) &&
(di->xdi_LowCyl || di->xdi_HighCyl != 79))
SPrintF(fd, buf, "-disk image %ld (%s, %ld to %ld)",
di->xdi_EntryNumber, di->xdi_TrackSectors == 22 ?
"HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
else
SPrintF(fd, buf, "-disk image %ld (%s)",
di->xdi_EntryNumber, di->xdi_TrackSectors == 22 ? "HD" : "DD");
}
fd->fd_Flags &= ~(CHKXNAMEFLAGS);
fd->fd_Name = buf;
PrintCHKXFile(fd);
if(di->xdi_TextInfo)
{
struct xadTextInfo *ti;
ULONG flags, i = 1, linknum;
for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
{
if(ti->xti_Size && ti->xti_Text)
{
flags = fd->fd_Flags;
fd->fd_Flags &= ~(CHKXNAMEFLAGS);
fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
fd->fd_RecurseDepth++;
linknum = fd->fd_LinkNum;
fd->fd_LinkNum = 0;
SPrintF(fd, buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
PrintCHKXErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
--fd->fd_RecurseDepth;
fd->fd_Flags = flags;
fd->fd_LinkNum = linknum;
}
++i;
}
}
/* check bootblock here - special outhook for bootblock extraction */
if(!di->xdi_LowCyl) /* boot check only, when first block! */
{
struct Hook hook = {{0,0},(ULONG (*)()) OutHookCheckX, 0};
fd->fd_Memory = buf;
hook.h_Data = fd;
xadDiskUnArc(ai, XAD_ENTRYNUMBER, di->xdi_EntryNumber,
XAD_OUTHOOK, &hook, XAD_PROGRESSHOOK, &breakhook,
trypwd ? XAD_PASSWORD : TAG_IGNORE, fd->fd_Password,
TAG_DONE);
if(fd->fd_Flags & CHECKXFLAG_BBEXTRACTED) /* special hook return code! */
{
struct xvsBootInfo *bi;
fd->fd_Flags &= ~CHECKXFLAG_BBEXTRACTED; /* clear flag */
if((bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO)))
{
bi->xvsbi_Bootblock = buf;
if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
{
PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
++fd->fd_NumVirus;
}
xvsFreeObject(bi);
}
else
PrintCHKXErr(fd, CHKXERR_NOBOOTVIRUS);
}
else
PrintCHKXErr(fd, CHKXERR_NOBOOTVIRUS);
}
if((aid = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
{
struct TagItem ti[5];
struct xadClient *cl;
ti[0].ti_Tag = XAD_INSIZE;
ti[0].ti_Data = buflength;
ti[1].ti_Tag = XAD_ENTRYNUMBER;
ti[1].ti_Data = di->xdi_EntryNumber;
ti[2].ti_Tag = XAD_PROGRESSHOOK;
ti[2].ti_Data = (ULONG) &breakhook;
ti[3].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
ti[3].ti_Data = (ULONG) fd->fd_Password;
ti[4].ti_Tag = TAG_MORE;
ti[4].ti_Data = (ULONG) tih;
if(!(err = xadGetDiskInfo(aid, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
XAD_INDISKARCHIVE, ti, TAG_DONE)))
{
if(aid->xai_Flags & XADAIF_FILECORRUPT)
{
++fd->fd_CorruptedArchives;
PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", aid->xai_Client->xc_ArchiverName);
}
else
PrintCHKXTxt(fd, "%s (FILESYSTEM)", aid->xai_Client->xc_ArchiverName);
CheckArcFiles(fd, aid, 1);
cl = aid->xai_Client->xc_Next;
xadFreeInfo(aid);
while(cl) /* multiple filesystems */
{
if(!xadGetDiskInfo(aid, XAD_NOEMPTYERROR, 1, XAD_INDISKARCHIVE, ti,
XAD_PROGRESSHOOK, &breakhook, XAD_STARTCLIENT, cl, TAG_DONE))
{
if(aid->xai_Flags & XADAIF_FILECORRUPT)
{
++fd->fd_CorruptedArchives;
PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", aid->xai_Client->xc_ArchiverName);
}
else
PrintCHKXTxt(fd, "%s (FILESYSTEM)", aid->xai_Client->xc_ArchiverName);
CheckArcFiles(fd, aid, 1);
cl = aid->xai_Client->xc_Next;
xadFreeInfo(aid);
}
else
cl = 0;
}
}
else
{
if((err == XADERR_PASSWORD) && !numloop)
{
if(!trypwd && fd->fd_Password[0])
{
++trypwd; err = 0; numloop = -2;
}
else
{
struct Library *xpkbase;
if((fd->fd_Flags & CHECKXFLAG_ASKPWD) && (xpkbase = OpenLibrary(XPKNAME, 4)))
{
if(!XpkPassRequestTags(XPK_PasswordBuf, fd->fd_Password, XPK_PassBufSize,
PASSWORDSIZE, XPK_PassTitle, name, TAG_DONE))
{
numloop = -1; err = 0;
++trypwd;
}
CloseLibrary(xpkbase);
}
}
}
if(err != XADERR_FILESYSTEM && err)
PrintCHKXErr(fd, XADERR_OFFSET + err);
err = 0;
}
xadFreeObjectA(aid, 0);
}
if(++numloop)
{
di = di->xdi_Next;
numloop = 0;
}
else
++numloop;
} /* while */
fd->fd_Flags = flags;
FreeMem(buf, 1024+512);
} /* AllocMem buffer */
else
err = CHKXERR_NOMEMORY;
} /* is there a disk entry? */
if(!OpenParentDir(fd))
err = CHKXERR_OPENDIR;
}
xadFreeInfo(ai);
} /* xadGetInfo */
else if(!xadGetDiskInfo(ai, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
XAD_INSIZE, buflength, TAG_MORE, tih))
{
struct xadClient *cl;
ULONG isvalid = 1;
if(ai->xai_Flags & XADAIF_FILECORRUPT)
{
++fd->fd_CorruptedArchives;
PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
}
else
PrintCHKXTxt(fd, "%s (FILESYSTEM)", ai->xai_Client->xc_ArchiverName);
if(fd->fd_Flags & CHECKXFLAG_NOUNTRACK)
{
if(buffer)
err = DoFileUnLink(fd, buffer, buflength);
}
else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
err = CHKXERR_OPENERR;
else
{
CheckArcFiles(fd, ai, 1);
while(isvalid && (cl = ai->xai_Client->xc_Next))
{
xadFreeInfo(ai);
if(!xadGetDiskInfo(ai, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
XAD_INSIZE, buflength, XAD_STARTCLIENT, cl, TAG_MORE, tih))
{
if(ai->xai_Flags & XADAIF_FILECORRUPT)
{
++fd->fd_CorruptedArchives;
PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
}
else
PrintCHKXTxt(fd, "%s (FILESYSTEM)", ai->xai_Client->xc_ArchiverName);
CheckArcFiles(fd, ai, 1);
}
else
isvalid = 0;
}
if(!OpenParentDir(fd))
err = CHKXERR_OPENDIR;
}
if(isvalid)
xadFreeInfo(ai);
}
else if(buffer)
err = DoFileUnLink(fd, buffer, buflength);
fd->fd_Name = arcname;
xadFreeObjectA(ai, 0);
}
else
err = CHKXERR_NOMEMORY;
return err;
}
/* Tries to unlink a file. When the file was linked, we call DoGetVirus
for the two parts to check if they may be archives, else we call
DoFileUnCrunch.
*/
static LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = CHKXERR_NOMEMORY;
struct xfdLinkerInfo *xli;
if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
{
xli->xfdli_Buffer = buffer;
xli->xfdli_BufLen = buflength;
if(xfdRecogLinker(xli))
{
PrintCHKXTxt(fd, xli->xfdli_LinkerName);
if(fd->fd_Flags & CHECKXFLAG_NOUNLINK)
ret = DoFileUnCrunch(fd, buffer, buflength);
else if(xfdUnlink(xli))
{
ULONG flags;
fd->fd_Flags |= CHECKXFLAG_LINKED;
++fd->fd_RecurseDepth;
++fd->fd_LinkNum;
flags = fd->fd_Flags;
fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
xli->xfdli_SaveLen1));
++fd->fd_LinkNum;
fd->fd_Flags = flags; /* CHECKXFLAG_NOFREEMEM is cleared */
PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
xli->xfdli_SaveLen2));
ret = 0;
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xli->xfdli_Error;
}
else
ret = DoFileUnCrunch(fd, buffer, buflength);
xfdFreeObject(xli);
}
return ret;
}
/* Tries to decrunch a file. When it is crunched, we decrunch it and call
DoGetVirus to start the loop again. Else we call unstripping.
*/
static LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = CHKXERR_NOMEMORY;
struct xfdBufferInfo *xbi;
if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
{
xbi->xfdbi_SourceBuffer = buffer;
xbi->xfdbi_SourceBufLen = buflength;
xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
if(xfdRecogBuffer(xbi))
{
struct Library *xpkbase;
STRPTR buf = 0;
ULONG buflen = 0;
PrintCHKXTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
"%s", xbi->xfdbi_PackerName);
if(fd->fd_Flags & CHECKXFLAG_ASKPWD && (xpkbase =
OpenLibrary(XPKNAME, 4)))
{
ASSIGN_XPK
if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
{
buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
xbi->xfdbi_MaxSpecialLen;
if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
{
if(!XpkPassRequestTags(XPK_PasswordBuf, buf, XPK_PassTitle, fd->fd_Name,
XPK_PassBufSize, buflen, TAG_DONE))
xbi->xfdbi_Special = buf;
}
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
{
if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, XPK_PassTitle, fd->fd_Name, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
{
if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, XPK_PassTitle, fd->fd_Name, TAG_DONE))
xbi->xfdbi_Special = &buflen;
}
CloseLibrary(xpkbase);
}
if(fd->fd_Flags & CHECKXFLAG_NODECRUNCH)
ret = DoFileStrip(fd, buffer, buflength);
else if(xfdDecrunchBuffer(xbi))
{
if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
{
fd->fd_Flags |= CHECKXFLAG_ADDRESS;
PrintCHKXErr(fd, SaveUncrFile(fd, buffer, buflength));
}
fd->fd_Flags |= CHECKXFLAG_CRUNCHED;
FreeCrunchMemList(fd, buffer);
++fd->fd_RecurseDepth;
if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufLen)))
{
PrintCHKXErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
xbi->xfdbi_TargetBufSaveLen));
}
else
FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
--fd->fd_RecurseDepth;
}
else
ret = XFDERR_OFFSET + xbi->xfdbi_Error;
if(buf)
FreeMem(buf, buflen);
}
else
ret = DoFileStrip(fd, buffer, buflength);
xfdFreeObject(xbi);
}
return ret;
}
/* Tries to strip useless hunks in a file. When there are some, we remove
them and call DoGetVirus to start the loop again. Else we finish.
When either unlinking or uncrunching happened in past loops, we may
save the file when there was SAVE option.
*/
static LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
{
LONG ret = 0;
ULONG reslength = buflength;
if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
CHECKXFLAG_NOSTRIP))
xfdStripHunks(buffer, buflength, &reslength,
XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
/* errors are not interpreted */
if(buflength > reslength)
{
fd->fd_Flags |= CHECKXFLAG_STRIPPED;
PrintCHKXTxt(fd, "%ld bytes stripped", buflength-reslength);
ret = DoGetVirus(fd, buffer, reslength);
}
else if(!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
ret = SaveUncrFile(fd, buffer, buflength);
FreeCrunchMemList(fd, buffer);
return ret;
}
/* Print file name */
static void PrintCHKXFile(struct FileData *fd)
{
STRPTR name = fd->fd_Name;
UBYTE i;
if((fd->fd_Flags & CHECKXFLAG_NAMEPRINTED))
return;
else if(fd->fd_Flags & CHECKXFLAG_SHORTNAME)
name = FilePart(name);
if(fd->fd_Flags & CHECKXFLAG_DEBUG)
{
if(fd->fd_Flags & CHECKXFLAG_CRC)
KPrintf(fd, (fd->fd_Flags & CHECKXFLAG_CRCVALID) ? "%08lx " :
"-------- ", fd->fd_CRC32);
for(i = 1; i < fd->fd_RecurseDepth; ++i)
KPutC('*', fd);
KPrintf(fd, fd->fd_LinkNum ? "%s.%ld\n" : "%s\n", name, fd->fd_LinkNum);
}
if(fd->fd_LogFileFH)
{
if(fd->fd_Flags & CHECKXFLAG_CRC)
FPrintf(fd->fd_LogFileFH, (fd->fd_Flags & CHECKXFLAG_CRCVALID) ?
"%08lx " : "-------- ", fd->fd_CRC32);
for(i = 1; i < fd->fd_RecurseDepth; ++i)
FPutC(fd->fd_LogFileFH, '*');
FPrintf(fd->fd_LogFileFH, fd->fd_LinkNum ? "%s.%ld\n" : "%s\n",
name, fd->fd_LinkNum);
}
if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
{
if(fd->fd_Flags & CHECKXFLAG_CRC)
Printf((fd->fd_Flags & CHECKXFLAG_CRCVALID) ? "%08lx " : "-------- ",
fd->fd_CRC32);
for(i = 1; i < fd->fd_RecurseDepth; ++i)
FPutC(Output(), '*');
Printf(fd->fd_LinkNum ? "%s.%ld\n" : "%s\n", name, fd->fd_LinkNum);
}
fd->fd_Flags |= CHECKXFLAG_NAMEPRINTED;
}
static void PrintCHKXErr(struct FileData *fd, LONG err)
{
if(err)
{
STRPTR txt = 0, txt2;
if(err > XFDERR_OFFSET)
{
++fd->fd_XFDErrors;
txt2 = "XFD-Error %ld: %s";
err -= XFDERR_OFFSET;
txt = xfdGetErrorText(err);
}
else if(err > XADERR_OFFSET)
{
++fd->fd_XADErrors;
txt2 = "XAD-Error %ld: %s";
err -= XADERR_OFFSET;
txt = xadGetErrorText(err);
}
else if(err > CHXWARN_OFFSET)
{
++fd->fd_CHKXWarnings;
txt2 = "CheckX-Warning %ld: %s";
switch(err)
{
case CHKXWARN_NOVIRUS: txt = "Virus-Checking disabled!"; break;
case CHKXWARN_XVSSELFTEST:txt = "The xvs.library is modified, maybe the system is virus infected!"; break;
case CHKXWARN_MEMVIRUS: txt = "Your system memory was virus infected!"; break;
case CHKXWARN_EMPTY: txt = "file is empty"; break;
}
err -= CHXWARN_OFFSET;
}
else
{
++fd->fd_CHKXErrors;
txt2 = "CheckX-Error %ld: %s";
switch(err)
{
case CHKXERR_NOMEMORY: txt = "not enough memory"; break;
case CHKXERR_EXAMINEERR: txt = "examining failed"; break;
case CHKXERR_OPENERR: txt = "opening file failed"; break;
case CHKXERR_READ: txt = "reading failed"; break;
case CHKXERR_SCANERR: txt = "directory scan failed"; break;
case CHKXERR_BREAK: txt = "user break"; break;
case CHKXERR_OPENDIR: txt = "opening directory failed"; break;
case CHKXERR_RESOURCE: txt = "needed resource not available"; break;
case CHKXERR_NOBOOTVIRUS: txt = "could not check for bootblock virus"; break;
case CHKXERR_WRITE: txt = "writing failed"; break;
case CHKXERR_NOVIRUS: txt = "could not check for virus"; break;
case CHKXERR_NOMEMORYARC: txt = "not enough memory for full tests"; break;
case CHKXERR_NOSECTOR: txt = "could not check sectors"; break;
}
}
PrintCHKXTxt(fd, txt2, err, txt);
}
}
/* Print type text */
static void PrintCHKXTxt(struct FileData *fd, STRPTR txt, ...)
{
UBYTE i, j;
if(fd->fd_Flags & CHECKXFLAG_MASTERTEXT)
j = 0;
else
{
j = fd->fd_RecurseDepth;
if(fd->fd_CRC32) j+= 9;
PrintCHKXFile(fd);
}
if(fd->fd_Flags & CHECKXFLAG_DEBUG)
{
for(i = 0; i < j; ++i)
KPutC(' ', fd);
RawDoFmt(txt, &txt+1, (void (*)()) KPutC, fd);
KPutC('\n', fd);
}
if(fd->fd_LogFileFH)
{
for(i = 0; i < j; ++i)
FPutC(fd->fd_LogFileFH, ' ');
VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
FPutC(fd->fd_LogFileFH, '\n');
Flush(fd->fd_LogFileFH);
}
if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
{
for(i = 0; i < j; ++i)
FPutC(Output(), ' ');
VPrintf(txt, &txt+1);
FPutC(Output(), '\n');
}
}
/* Add memory to the memory list. */
static LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
{
struct CrunchMemList *ml;
if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
MEMF_ANY)))
{
ml->cml_Next = fd->fd_MemList;
ml->cml_MemoryRegion = reg;
ml->cml_MemorySize = size;
fd->fd_MemList = ml;
return 0;
}
return CHKXERR_NOMEMORY;
}
/* Free memory from the memory list. */
static void FreeCrunchMemList(struct FileData *fd, APTR reg)
{
struct CrunchMemList mc, *ml = &mc;
if(fd->fd_Flags & CHECKXFLAG_NOFREEMEM)
return;
for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
{
if(ml->cml_Next->cml_MemoryRegion == reg)
{
struct CrunchMemList *m;
m = ml->cml_Next;
ml->cml_Next = m->cml_Next;
FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
FreeMem(m, sizeof(struct CrunchMemList));
}
}
fd->fd_MemList = mc.cml_Next;
}
/* Save file, when SAVE option and file was crunched or linked. */
static LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
{
BPTR filefh, cd;
LONG ret = 0, i = 0;
UBYTE name[50];
UBYTE nbuf[256];
if(!(fd->fd_SaveDirL && (fd->fd_Flags & CHKXSAVEFLAGS)))
return 0;
SPrintF(fd, name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
fd->fd_LinkNum);
cd = CurrentDir(fd->fd_SaveDirL);
while(!ret && name[i])
{
for(;name[i] && name[i] != '/'; ++i)
nbuf[i] = name[i];
if(name[i] == '/')
{
nbuf[i] = 0;
if((filefh = Lock(nbuf, SHARED_LOCK)))
UnLock(filefh);
else
{
if((filefh = CreateDir(nbuf)))
UnLock(filefh);
else
ret = CHKXERR_OPENERR;
}
nbuf[i] = name[i];
++i;
}
}
if(!ret)
{
if((filefh = Open(name, MODE_NEWFILE)))
{
if(Write(filefh, buf, size) != size)
ret = CHKXERR_WRITE;
Close(filefh);
}
else
ret = CHKXERR_OPENERR;
}
CurrentDir(cd);
return ret;
}
static ASM(void) SPrintF_putfunc(REG(d0, UBYTE data), REG(a3, STRPTR *a))
{
*((*a)++) = data;
}
static void SPrintF(struct FileData *fd, STRPTR buf, STRPTR format, ...)
{
STRPTR buf2 = buf;
RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
(void(*)()) SPrintF_putfunc, &buf2);
}
static ASM(void) KPutC(REG(d0, ULONG c), REG(a3, struct FileData *fd))
{
RawPutChar(c);
}
static void KPrintf(struct FileData *fd, STRPTR fmt, ...)
{
RawDoFmt(fmt, &fmt + 1, (void (*)()) KPutC, fd);
}
#ifdef __SASC
#undef SysBase
#define SysBase sysbase
#endif
static ASM(LONG) BreakHookCheckX(void)
{
return (SetSignal(0L,0L) & SIGBREAKF_CTRL_C) ? 0 : XADPIF_OK;
}